home *** CD-ROM | disk | FTP | other *** search
- (* Module for M2Amiga (soon to by cycloned). If you want to
- translate this to another HLL, then watch for the
- procedure sizes, they should fit into a 256Byte
- cache for best results *)
-
-
-
- MODULE ClockFreq;
-
-
- IMPORT ED: ExecD;
- IMPORT EL: ExecL;
- IMPORT DL: DosL;
- FROM Hardware IMPORT ciaa, ciab;
-
- IMPORT R;
- IMPORT CO: Conversions;
- IMPORT LRC: LongRealConversions;
-
- FROM CiaTimer IMPORT CiaStartTimer, CiaStopTimer, CiaGetDiff;
-
- FROM SYSTEM IMPORT CAST, ADDRESS, ADR, ASSEMBLE, BITSET;
-
-
-
- CONST
- Version= "$VER: ClockFreq 1.0 (16.08.1996)";
-
- VAR
- OuterLoopVal, InnerLoopVal: INTEGER; (* Times to run through the NOP-Loop *)
- ClocksPerNOP: LONGINT; (* How many clocks does a NOP use on a specific CPU *)
-
-
-
- (* Some custom IO *)
- (*$CopyDyn:= FALSE *)
- PROCEDURE W(S: ARRAY OF CHAR);
- VAR
- Bool{R.D7}: BOOLEAN;
- BEGIN
- Bool:= DL.PutStr(ADR(S));
- END W;
-
- PROCEDURE WI(LI, W: LONGINT);
- VAR
- Bool{R.D7}, err: BOOLEAN;
- S: ARRAY [0..15] OF CHAR;
- BEGIN
- CO.ValToStr(LI, FALSE, S, 10, W, " ", err);
- Bool:= DL.PutStr(ADR(S));
- END WI;
-
- PROCEDURE WR(LR: LONGREAL; M, N: LONGINT);
- VAR
- Bool{R.D7}, err: BOOLEAN;
- S: ARRAY [0..15] OF CHAR;
- BEGIN
- LRC.RealToStr(LR, S, M, N , FALSE, err);
- Bool:= DL.PutStr(ADR(S));
- END WR;
-
-
-
-
- (* Measure frequency by doing nothing ...
- A NOP is perfect for measuring MHz, because it synchronises the
- cpu-pipelines and it is therefore easy to say how much clocks
- are needed for one NOP. The influence of the loops (DBF) is
- compensated in a second measuring. *)
-
- CONST
- NumNOPs= 40;
-
- (*$EntryExitCode:= FALSE *)
- PROCEDURE NOPLoop(InnerLoop{R.D5}, OuterLoop{R.D6}: INTEGER);
- BEGIN
- ASSEMBLE(
- OLoop:
- MOVE.W D5, D0
- Loop:
- NOP (*Inst 1*)
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP (*Inst 21*)
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP (* 41, these 6 are for overhead measuring *)
- NOP
- NOP
- NOP
- NOP
- NOP
- DBF D0, Loop
- DBF D6, OLoop
- RTS
- END);
- END NOPLoop;
-
-
- (*$EntryExitCode:= FALSE *)
- PROCEDURE Overhead(InnerLoop{R.D5}, OuterLoop{R.D6}: INTEGER);
- BEGIN
- ASSEMBLE(
- OLoop:
- MOVE.W D5, D0
- Loop:
- NOP (* 41, these 6 are for overhead measuring *)
- NOP
- NOP
- NOP
- NOP
- NOP
- DBF D0, Loop
- DBF D6, OLoop
- RTS
- END);
- END Overhead;
-
-
-
-
-
-
- PROCEDURE SlowCalc;
- VAR
- Ticks: LONGINT; (* Ticks per second *)
- Used: LONGINT; (* used ticks *)
- HelpR: LONGREAL;
-
- BEGIN
- Ticks:= EL.execBase^.eClockFrequency;
-
- (* Interrupts must be diabled to measure frequency as good as possible.
- This forbids using ReadEClock, and forbids to combine two
- cia-timers to one (???). So the maximum tick-time is 2^16. *)
- EL.Disable;
-
- (* Approx. time for 1 loop, to see how many loops fit in 2^16-1 ticks *)
- CiaStartTimer;
- NOPLoop(InnerLoopVal, 0);
- CiaStopTimer;
- Used:= CiaGetDiff();
-
- IF Used > 0 THEN
- OuterLoopVal:= (65535 DIV Used) ;
-
- (* REPEAT for handling unexpected circumstances... *)
- REPEAT
- DEC(OuterLoopVal);
-
- NOPLoop(InnerLoopVal, 0); (* Preload Cache \ *)
- CiaStartTimer; (* - should fit in 256B-cache *)
- CiaStopTimer;
- CiaStartTimer;
- NOPLoop(InnerLoopVal, OuterLoopVal); (* / *)
- CiaStopTimer;
- Used:= CiaGetDiff();
- UNTIL (Used > 0) OR (OuterLoopVal < 0); (* Used = 0 if ticks >=2^16 *)
-
- IF OuterLoopVal >= 0 THEN
- (* Overhead timing *)
- Overhead(InnerLoopVal, 0); (* Preload Cache *)
- CiaStartTimer;
- CiaStopTimer;
- CiaStartTimer;
- Overhead(InnerLoopVal, OuterLoopVal);
- CiaStopTimer;
-
- EL.Enable;
-
- DEC(Used, CiaGetDiff());
-
- HelpR:= LONGREAL((InnerLoopVal+1)*ClocksPerNOP*(OuterLoopVal+1)); (* DBF needs +1 *)
- HelpR:= HelpR / (LONGREAL(Used) / LONGREAL(Ticks));
-
- (* Print results. "/ 25000", because result should be in Mhz and not Hz and
- because 40 NOPs used and not one *)
- W("CPU: "); WR(HelpR / 25000., 10, 5); W(" MHz\n");
- W("Ticks: "); WI(Used, 10); W("\n");
- W("Ticks/s:"); WI(Ticks, 10); W("\n");
- (* W("Loops: "); WI(OuterLoopVal, 10); W("\n"); *)
- END;
- ELSE
- EL.Enable;
- W("Measurement impossible. Enable cache or install fastram ...");
- END;
- END SlowCalc;
-
-
-
-
-
-
-
-
-
- VAR
- Bool, CacheChk: BOOLEAN;
- BEGIN
- (* Show BOLD version to user *)
- W("\e[1m"); Bool:= DL.PutStr(ADR(Version)+6); W("\e[0m\n");
-
-
- (* Adapt to CPU *)
- CacheChk:= TRUE;
- IF ED.af7 IN EL.execBase^.attnFlags THEN (* supported by all 060-boards??? *)
- W("060 mode\n");
- InnerLoopVal:= 99;
- ClocksPerNOP:= 9;
- ELSIF ED.m68040 IN EL.execBase^.attnFlags THEN
- W("040 mode\n");
- InnerLoopVal:= 99;
- ClocksPerNOP:= 8;
- ELSIF ED.m68020 IN EL.execBase^.attnFlags THEN
- W("020|030 mode\n");
- InnerLoopVal:= 199;
- ClocksPerNOP:= 2;
- ELSE
- W("000|010 mode\n");
- InnerLoopVal:= 69;
- ClocksPerNOP:= 4;
- CacheChk:= FALSE;
- END;
-
- (* Test for optimal conditions *)
- IF CacheChk THEN (* verify that cache is turned on *)
- IF ~(ED.enableI IN EL.CacheControl(ED.CacheFlagSet{}, ED.CacheFlagSet{})) THEN
- W("\e[3mInstructionCache not enabled, result will be inexact ...\e[0m\n");
- END;
- ELSE (* check that code is in "fast" on 68000/010 *)
- IF ~(ED.fast IN EL.TypeOfMem(ADR(NOPLoop))) THEN
- W("\e[3mProgram is not in fast ram, result will be inexact ...\e[0m\n");
- END;
- END;
-
- DL.Delay(5); (* SystemCalmDown *)
-
- SlowCalc;
-
- END ClockFreq.
-